package com.example.springbootflowabledemo.service.impl;

import com.example.springbootflowabledemo.domian.dto.TodoListDto;
import com.example.springbootflowabledemo.domian.resp.MyProcessResp;
import com.example.springbootflowabledemo.domian.resp.PageResp;
import com.example.springbootflowabledemo.service.FlowableService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class FlowableServiceImpl implements FlowableService {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    private static final String BPMN_FILE_SUFFIX = ".bpmn";

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deployment(String name, InputStream in) {
        Deployment deploy = repositoryService.createDeployment().addInputStream(name + BPMN_FILE_SUFFIX, in).name(name).deploy();
        log.info("流程部署id={}", deploy.getId());
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
        log.info("(启动流程使用)流程processDefinitionId={}", processDefinition.getId());
    }


    @Override
    public void activate(String procdefId, Map<String, Object> variables) {
        boolean suspended = repositoryService.getProcessDefinition(procdefId).isSuspended();
        if (suspended) {
            throw new RuntimeException("流程定义被挂起, 无法启动.");
        }
        Authentication.setAuthenticatedUserId("10086");
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(procdefId, variables);
        log.info("流程id={}", processInstance.getId());

        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
        for (Task task : tasks) {
            log.info("流程id={}, 下次执行task={}", processInstance.getId(), task.getId());
        }
    }

    @Override
    public void complete(String taskId, Map<String, Object> variables) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task.isSuspended()) {
            log.error("流程实例被挂起, 无法处理task, taskId={}, processId={}", taskId, task.getProcessInstanceId());
            throw new RuntimeException("流程实例被挂起, 无法处理task.");
        }
//        taskService.setAssignee(taskId, "10010");
        taskService.complete(taskId, variables);
    }

    @Override
    public void deleteDeploy(String deployId) {
        log.info("删除流程定义成功deployId={}", deployId);
        // true 级联删除, 删除该流程定义相关的所有数据
        repositoryService.deleteDeployment(deployId, true);
    }

    @Override
    public String updateDeployState(String procdefId, Integer state) {
        if (state == null) {
            log.error("deployId={}, 激活/挂起流程定义状态错误.", procdefId);
            return "激活/挂起流程定义状态错误.";
        }
        if (1 == state) {
            repositoryService.activateProcessDefinitionById(procdefId, true, new Date());
            return "流程定义激活成功.";
        }

        if (2 == state) {
            repositoryService.suspendProcessDefinitionById(procdefId, true, new Date());
            return "流程定义挂机成功.";
        }
        return "激活/挂起流程定义失败.";
    }

    @Override
    public String updateProcessState(String processInstanceId, Integer state) {
        if (state == null) {
            log.error("processInstanceId={}, 激活/挂起流程实例失败, 状态错误", processInstanceId);
            return "激活/挂起流程实例状态错误.";
        }

        if (1 == state) {
            runtimeService.activateProcessInstanceById(processInstanceId);
            return "流程实例激活成功.";
        }

        if (2 == state) {
            runtimeService.suspendProcessInstanceById(processInstanceId);
            return "流程实例挂机成功.";
        }
        return "激活/挂起流程实例失败.";
    }

    @Override
    public List<MyProcessResp> myStartProcess() {
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery().startedBy("10086").orderByProcessInstanceStartTime().desc().list();

        List<MyProcessResp> resps = new ArrayList<>();
        for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
            MyProcessResp resp = new MyProcessResp();
            resp.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
            resp.setStartDate(historicProcessInstance.getStartTime());
            HistoricProcessInstanceEntityImpl historicProcessInstanceEntity = (HistoricProcessInstanceEntityImpl) historicProcessInstance;
            resp.setProcessInstanceId(historicProcessInstanceEntity.getProcessInstanceId());
            resp.setEndDate(historicProcessInstanceEntity.getEndTime());
            resp.setProcessDefinitionName(historicProcessInstance.getProcessDefinitionName());
            resps.add(resp);
        }
        return resps;
    }

    @Override
    public PageResp myTodoList(Integer pageNum, Integer pageSize) {
        //当前登录用户
        String user = "MaoLg";
        PageResp resp = new PageResp();
        //查询属于我的节点正在跑的总数
        resp.setTotal(runtimeService.createProcessInstanceQuery().variableValueEquals(user).count());

        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().variableValueEquals(user).listPage(pageSize * (pageNum - 1), pageSize);
        // 获取当前我要处理流程的信息, 并获取  task信息
        for (ProcessInstance processInstance : processInstances) {
            TodoListDto todoListDto = new TodoListDto();
            Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
            todoListDto.setProcessName(processInstance.getProcessDefinitionName());
            todoListDto.setTaskId(task.getId());
            Map<String, Object> variables = taskService.getVariables(task.getId());

            todoListDto.setMsg(variables.get("day").toString());
            resp.getList().add(todoListDto);
        }
        return resp;
    }


}
